package com.hxkj.service.impl;


import com.alibaba.druid.util.StringUtils;
import com.hxkj.dao.UserDao;
import com.hxkj.domain.enums.FunctionType;
import com.hxkj.domain.enums.UserExceptionEnum;
import com.hxkj.domain.po.*;
import com.hxkj.service.UserService;
import com.hxkj.token.TokenGenerator;
import com.hxkj.token.enums.TokenExceptionEnum;
import com.hxkj.token.po.LoginToken;
import com.hxkj.token.po.Token;
import com.hxkj.token.service.TokenInformationConverter;
import com.hxkj.token.utils.TokenUtils;
import com.hxkj.utils.MD5Utils;
import com.platform.common.domain.exception.CustomException;
import com.platform.common.domain.exception.CustomMessageException;
import com.platform.common.domain.result.ResultDataStruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * 用户service
 * <p>
 * Created by chenwei on 2018/5/15.
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService, TokenInformationConverter<AuthUser> {

    /**
     * 管理员角色类型
     */
    private final static Long ADMIN = 1L;

    @Value("${auth.app.key}")
    private String appKey;

    @Resource
    private UserDao userDao;

    @Resource
    private TokenUtils tokenUtils;

    @Resource
    private TokenGenerator tokenGenerator;

    @Override
    public ResultDataStruct<LoginToken> login(AuthUser user) throws Exception {
        ResultDataStruct resultMessage = new ResultDataStruct();
        if (StringUtils.isEmpty(user.getUserAccount()) || StringUtils.isEmpty(user.getPassword())) {
            resultMessage.setCode(UserExceptionEnum.USER_ACCOUNT_IS_NULL.getCode());
            resultMessage.setMessage(UserExceptionEnum.USER_ACCOUNT_IS_NULL.getMsg());
            return resultMessage;
        }
        // 据account获得用户信息
        String password = user.getPassword();
        AuthUser authUser = userDao.findByAccount(user.getUserAccount());
        if (authUser != null) {

            // 简单验证密码 需更换
            Boolean verification = MD5Utils.verificationPassword(authUser, password);

            if (verification) {
                LoginToken loginToken = tokenGenerator.generatorLoginToken(null, authUser.getUserAccount(), String.valueOf(authUser.getUserId()));
                log.debug("用户:{}登录成功", authUser);
                resultMessage.setCode(200);
                resultMessage.setMessage("成功");
                // 返回生成的token
                resultMessage.setData(loginToken);
            } else {
                resultMessage.setCode(400);
                resultMessage.setMessage("密码错误");
                return resultMessage;
            }
        } else {
            resultMessage.setCode(UserExceptionEnum.USER_NOT_EXIST.getCode());
            resultMessage.setMessage(UserExceptionEnum.USER_NOT_EXIST.getMsg());
            return resultMessage;
        }
        return resultMessage;
    }

    @Override
    public ResultDataStruct<AuthUser> getUser(String account) throws Exception {
        ResultDataStruct<AuthUser> authUserResultDataStruct = new ResultDataStruct<>();
        AuthUser authUser = userDao.findByAccount(account);
        if (authUser != null) {
            authUserResultDataStruct.setData(authUser);
            authUserResultDataStruct.setCode(200);
            authUserResultDataStruct.setMessage("成功");
        } else {
            authUserResultDataStruct.setMessage(UserExceptionEnum.USER_NOT_EXIST.getMsg());
            authUserResultDataStruct.setCode(UserExceptionEnum.USER_NOT_EXIST.getCode());
        }
        return authUserResultDataStruct;
    }


    @Override
    public ResultDataStruct<Set<String>> findRolesByAccount(String account) throws Exception {
        ResultDataStruct<Set<String>> resultDataStruct = new ResultDataStruct();
        try {
            Set<String> strings = userDao.findRolesByAccount(account);

            resultDataStruct.setCode(200);
            resultDataStruct.setMessage("成功");
            resultDataStruct.setData(strings);
        } catch (Exception e) {
            resultDataStruct.setCode(UserExceptionEnum.GET_ROLE_BY_ACCOUNT_FAIL.getCode());
            resultDataStruct.setMessage(UserExceptionEnum.GET_ROLE_BY_ACCOUNT_FAIL.getMsg());
        }
        return resultDataStruct;
    }


    /**
     * 根据账户获取角色
     *
     * @param account
     * @return
     * @throws Exception
     */
    public AuthRole findRoleByAccount(String account, Long siteId) throws Exception {
        AuthRole authRole = userDao.getRoleByAccount(AuthUser.builder().userAccount(account).siteId(siteId).build());
        return authRole;
    }

    @Override
    public Set<String> findPermissionsByAccount(String account) throws Exception {
        // 获取拥有的站点
        Set<String> permissions = new HashSet<>();
        List<Site> sites = userDao.getUserSiteByAccount(account);
        if (sites.size() == 1) {
            Long siteId = sites.get(0).getSiteId();
            AuthRole authRole = this.findRoleByAccount(account, sites.get(0).getSiteId());
            // 若为管理员
            if (authRole.getRoleType() == 1) {
                permissions = userDao.findPermissionsBySite(siteId);
            }
        } else {
            permissions = userDao.findPermissionsByAccount(account);
        }
        return permissions;
    }

    @Override
    public List<FunctionMenu> findFunctionMenuByAccount(FunctionSite functionSite) throws Exception {
        // 若没有传递siteid
        if (StringUtils.isEmpty(functionSite.getSiteId())) {
            // 判断是否有唯一子站
            List<Site> sites = userDao.getUserSiteByAccount(functionSite.getUserAccount());
            if (sites.size() > 0) {
                Long siteId = sites.get(0).getSiteId();
                // 设置子站siteid
                functionSite.setSiteId(String.valueOf(siteId));
            }
        }
        AuthRole authRole = this.findRoleByAccount(functionSite.getUserAccount(), Long.valueOf(functionSite.getSiteId()));
        if (authRole == null) {
            throw new CustomMessageException(400, "该用户在站点:" + functionSite.getSiteId() + "下没有角色");
        }


        List<AuthFunction> functions;
        Long roleType = authRole.getRoleType();
        // 管理员获取站点下所有功能
        if (roleType != null && authRole.getRoleType() == ADMIN) {
            // 管理员获取站点下所有功能
            functions = userDao.findAllFunctionsBySite(Long.valueOf(functionSite.getSiteId()));
        } else {
            functions = userDao.findFunctions(functionSite.getUserAccount(), appKey, functionSite.getSiteId());
        }

        // 菜单
        List<FunctionMenu> menus = new ArrayList<>();
        if (functions != null) {
            // 第一次遍历 构建一级菜单
            for (AuthFunction item : functions) {
                if (Objects.equals(item.getFunctionType(), FunctionType.MENU.getCode()))
                    // 若父节点是根节点
                    if (item.getParentFunctionId() != null && -1 == item.getParentFunctionId()) {
                        menus.add(buildFunctionMenu(item));
                    }
            }
            // 第二次遍历 构建二级菜单
            for (AuthFunction item : functions) {
                if (Objects.equals(item.getFunctionType(), FunctionType.MENU.getCode()))
                    // 二级菜单的构建
                    if ((item.getParentFunctionId() != null && -1 != item.getParentFunctionId())) {
                        buildChildMenu(item, menus);
                    }
                if (Objects.equals(item.getFunctionType(), FunctionType.BUTTON.getCode()))
                    // 二级菜单的构建
                    if ((item.getParentFunctionId() != null && -1 != item.getParentFunctionId())) {
                        bulidButton(item, menus);
                    }
            }
        }

        return menus;
    }

    @Override
    public ResultDataStruct<List<AuthRole>> getRolesByAccount(String account) {
        ResultDataStruct<List<AuthRole>> listResultDataStruct = new ResultDataStruct<>();
        userDao.getRolesByAccount(appKey, account);
        return listResultDataStruct;
    }


    /**
     * 构建二级菜单
     *
     * @param function 功能
     * @param menus    菜单集合
     */
    private void buildChildMenu(AuthFunction function, List<FunctionMenu> menus) {
        for (FunctionMenu item : menus) {
            // 菜单遍历
            if (function.getParentFunctionId().equals(item.getFunctionId())) {
                List<FunctionMenu> childs = item.getChildren();
                // 判断当前菜单下的字菜单集合是否为空,为空则时行初始化
                if (childs == null) {
                    childs = new ArrayList<>();
                }
                // 添加菜单功能对象到二级菜单列表中
                childs.add(buildFunctionMenu(function));
                item.setChildren(childs);
            }
        }
    }


    /**
     * 构建功能
     *
     * @param function 功能
     * @param menus    菜单集合
     */
    private void bulidButton(AuthFunction function, List<FunctionMenu> menus) {
        for (FunctionMenu item : menus) {
            List<FunctionMenu> functionMenus = item.getChildren();
            if (functionMenus != null) {
                for (FunctionMenu chil : functionMenus) {
                    // 菜单遍历
                    if (function.getParentFunctionId().equals(chil.getFunctionId())) {
                        List<FunctionMenu> childs = chil.getButtons();
                        // 判断当前菜单下的字菜单集合是否为空,为空则时行初始化
                        if (childs == null) {
                            childs = new ArrayList<>();
                        }
                        // 添加菜单功能对象到二级菜单列表中
                        childs.add(buildFunctionMenu(function));
                        chil.setButtons(childs);
                    }
                }

            }
        }
    }


    /**
     * 生成菜单对象
     *
     * @param function 功能菜单
     */
    private FunctionMenu buildFunctionMenu(AuthFunction function) {
        FunctionMenu menuFunction = new FunctionMenu();
        menuFunction.setFunctionId(function.getFunctionId());
        menuFunction.setFunctionName(function.getFunctionName());
        menuFunction.setFunctionUri(function.getFunctionUri());
        menuFunction.setFunctionType(function.getFunctionType());
        menuFunction.setFunctionIcon(function.getFunctionIcon());
        menuFunction.setFunctionCode(function.getFunctionCode());
        return menuFunction;
    }


    public ResultDataStruct<AuthUser> getUserInfoByIdRemote(String userId) throws Exception {
        ResultDataStruct<AuthUser> authUserResultDataStruct = new ResultDataStruct<>();
        try {
            AuthUser AuthUser = userDao.getUserInfoById(userId);
            authUserResultDataStruct.setCode(200);
            authUserResultDataStruct.setMessage("成功");
            authUserResultDataStruct.setData(AuthUser);
        } catch (Exception e) {
            authUserResultDataStruct.setCode(UserExceptionEnum.GET_USER_BY_ID_FAIL.getCode());
            authUserResultDataStruct.setMessage(UserExceptionEnum.GET_USER_BY_ID_FAIL.getMsg());
        }
        return authUserResultDataStruct;
    }

    public ResultDataStruct<AuthUser> getUserInfoByTokenRemote(String accessToken) throws Exception {
        ResultDataStruct<AuthUser> authUserResultDataStruct = new ResultDataStruct<>();
        if (StringUtils.isEmpty(accessToken)) {
            throw new CustomException(UserExceptionEnum.ACCESSTOKEN_NOT_EXIST);
        }

        // reset
        Token token = tokenGenerator.validateToken(accessToken);
        if (token == null) {
            throw new CustomException(TokenExceptionEnum.TOKEN_EXPIRES_CODE);
        }
        AuthUser authUser = getUserInfo(token.getUserId());
        if (authUser == null) {
            authUserResultDataStruct.setCode(UserExceptionEnum.USER_NOT_EXIST.getCode());
            authUserResultDataStruct.setMessage(UserExceptionEnum.USER_NOT_EXIST.getMsg());
        } else {
            authUserResultDataStruct.setCode(200);
            authUserResultDataStruct.setMessage("成功");
            authUserResultDataStruct.setData(authUser);
        }
        return authUserResultDataStruct;
    }


    public AuthUser getUserInfo(String userId) throws Exception {
        AuthUser AuthUser = userDao.getUserInfoById(userId);
        return AuthUser;
    }


    @Override
    public AuthUser getUserInfoByToken(String accessToken) throws Exception {
        Token token = tokenGenerator.validateToken(accessToken);
        return userDao.getUserInfoById(token.getUserId());
    }

    @Override
    public AuthUser getUserInfoById(String userId) throws Exception {
        return userDao.getUserInfoById(userId);
    }
}
